<template>
  <ToolboxWindow
    :width="480"
    :show="show"
    @close="handleClose"
    :show-close="false"
  >
    <template #title>
      <div class="header-container">
        <div class="title-container">
          <el-icon><FolderOpened /></el-icon>
          <span>{{ caption }}</span>
        </div>
        <div v-if="showTree" class="button-container">
          <el-select
            size="small"
            style="width: 160px; margin-right: 24px"
            placeholder="关键字过滤 (交集)"
            :clearable="true"
            :suffix-icon="Filter"
            v-model="filterContent"
            multiple
            filterable
            allow-create
            default-first-option
            :reserve-keyword="false"
          >
            <el-option
              v-for="item in filterOptions"
              :key="`keywords_${item}`"
              :value="item"
            >
              <span class="keywords-options">{{ item }}</span>
            </el-option>
          </el-select>
          <el-button link @click="handleClear">
            <el-icon>
              <Delete />
            </el-icon>
          </el-button>
          <el-button link @click="handleCreate">
            <el-icon>
              <DocumentAdd />
            </el-icon>
          </el-button>
          <el-button link @click="handleReload">
            <el-icon>
              <Refresh />
            </el-icon>
          </el-button>
          <el-button link @click="handleClose" style="margin-right: 4px">
            <el-icon>
              <Close />
            </el-icon>
          </el-button>
        </div>
        <div v-if="showEditor">
          <el-button
            link
            :type="isCreate || isChanged ? 'primary' : ''"
            @click="handleSave"
            :disabled="selectedTags.length == 0 || !(isCreate || isChanged)"
            >保存</el-button
          >
          <el-button link @click="handleCancelEdit">
            {{ `${isCreate || isChanged ? "取消" : "返回"}` }}
          </el-button>
        </div>
      </div>
    </template>
    <div v-if="showTree" class="tree-wrapper">
      <el-checkbox-group
        v-model="flowStore.chartConfig.freeChart.appliedTemplateIndexList"
        @change="handleTreeCheckChange"
        class="tree-node-group"
        :max="chartLimit"
      >
        <el-checkbox
          v-for="item in treeDataSource"
          :value="item.id"
          :key="item.id"
        >
          <div class="custom-tree-node">
            <span>{{ item.label }}</span>
            <span class="node-button-container">
              <el-button
                type="primary"
                link
                @click="handleTreeNodeEdit(item.id)"
              >
                <el-icon><Edit /></el-icon>
              </el-button>
              <el-button
                type="danger"
                link
                @click="handleTreeNodeDelete(item.id)"
              >
                <el-icon><DocumentDelete /></el-icon>
              </el-button>
            </span>
          </div>
        </el-checkbox>
      </el-checkbox-group>
    </div>
    <div v-if="showEditor" class="editor-wrapper">
      <el-form size="small" :label-width="formLabelWidth">
        <!-- <el-divider /> -->
        <el-form-item label="模板标题">
          <el-input v-model="selectedTemplate.title"></el-input>
        </el-form-item>
        <!-- <el-form-item label="合计">
          <el-switch v-model="selectedTemplate.total"></el-switch>
        </el-form-item> -->
        <el-form-item label="统计系列">
          <el-select v-model="selectedSeriesIndex">
            <el-option
              v-for="(seriesItem, seriesIndex) in selectedTemplate.series"
              :label="seriesItem.name"
              :value="seriesIndex"
              :key="'series' + seriesIndex"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="">
          <el-button link @click="handleAddSeries">
            <el-icon><Plus /></el-icon>
            <span>添加系列</span>
          </el-button>
          <el-button
            link
            @click="handleRemoveSeries"
            :disabled="selectedTemplate.series.length == 1"
          >
            <el-icon><Minus /></el-icon>
            <span>删除系列</span>
          </el-button>
          <el-button
            link
            @click="handleMoveSeries(-1)"
            :disabled="
              selectedTemplate.series.length == 1 || selectedSeriesIndex == 0
            "
          >
            <el-icon><Top /></el-icon>
            <span>上移系列</span>
          </el-button>
          <el-button
            link
            @click="handleMoveSeries(1)"
            :disabled="
              selectedTemplate.series.length == 1 ||
              selectedSeriesIndex == selectedTemplate.series.length - 1
            "
          >
            <el-icon><Bottom /></el-icon>
            <span>下移系列</span>
          </el-button>
        </el-form-item>
        <el-form-item label="系列名">
          <el-input
            v-model="selectedTemplate.series[selectedSeriesIndex].name"
          ></el-input>
        </el-form-item>
        <el-form-item label="系列颜色">
          <el-color-picker
            v-model="selectedTemplate.series[selectedSeriesIndex].color"
          />
          <el-divider style="margin: 0 16px" direction="vertical" />
          <el-button
            link
            @click="handleRecolor"
            :style="{
              color: selectedTemplate.series[selectedSeriesIndex].color,
            }"
          >
            <el-icon style="transform: rotate(30deg)">
              <Brush />
            </el-icon>
            <span>随机</span>
          </el-button>
          <el-divider style="margin: 0 16px" direction="vertical" />
          <span
            :style="{
              color: selectedTemplate.series[selectedSeriesIndex].color,
            }"
            >{{ selectedTemplate.series[selectedSeriesIndex].color }}</span
          >
        </el-form-item>
        <el-form-item label="流量标签">
          <el-select
            v-model="selectedTemplate.series[selectedSeriesIndex].tags"
            multiple
            filterable
            clearable
            placeholder="选择需要统计的标签"
          >
            <el-option
              v-for="(tagItem, tagIndex) in tags"
              :key="'tagIitem' + tagIndex"
              :label="tagItem"
              :value="tagItem"
              :disabled="!isTagAvailable(tagItem)"
            />
          </el-select>
        </el-form-item>
        <el-divider />
        <el-form-item label="GUID">
          <el-text type="info">{{ selectedTemplate.guid }}</el-text>
        </el-form-item>
        <el-form-item label="创建">
          <el-text type="info">{{ selectedTemplate.createTime }}</el-text>
          <el-divider direction="vertical" />
          <el-text type="info">{{ selectedTemplate.createIP }}</el-text>
        </el-form-item>
        <el-form-item label="更新" v-if="!isCreate">
          <el-text type="info">{{ selectedTemplate.updateTime }}</el-text>
          <el-divider direction="vertical" />
          <el-text type="info">{{ selectedTemplate.updateIP }}</el-text>
        </el-form-item>
      </el-form>
    </div>
  </ToolboxWindow>
</template>

<script setup>
import { ref, computed, onMounted, onUnmounted, nextTick, h } from "vue";
import { ElMessage, ElMessageBox, ElNotification } from "element-plus";
import { Filter, Search } from "@element-plus/icons-vue";
import axios from "axios";
import dayjs from "dayjs";
import ToolboxWindow from "@/components/ToolboxWindow";
import useFlowStore from "@/store/flow.js";
import useSeatStore from "@/store/seat.js";
import { randomUUID, emulateRandomUUID } from "@/utils/uuid.js";
import { randomHexColor } from "@/utils/color.js";

const chartLimit = 3;

const flowStore = useFlowStore();
const seatStore = useSeatStore();

const caption = computed(
  () => `模板 ${isCreate.value ? "(新建)" : isChanged.value ? "(已编辑)" : ""}`
);
const show = computed(() => flowStore.chartConfig.freeChart.showMgr);
const showTemplateSelector = ref(true);
const emits = defineEmits(["apply"]);
const formLabelWidth = ref("60px");

const showTree = computed(
  () => showTemplateSelector.value && !selectedTemplate.value
);
const showEditor = computed(
  () => showTemplateSelector.value && selectedTemplate.value
);

const filterContent = ref([]);

const filterOptions = ref([
  "一室",
  "二室",
  "南",
  "北",
  "S",
  "N",
  "13",
  "14",
  "11",
  "01",
  "08",
  "波",
  "BO",
]);

const handleTreeCheckChange = (value) => {
  flowStore.chartConfig.freeChart.appliedTemplateList =
    flowStore.chartConfig.freeChart.chartTemplates.filter((item) =>
      value.includes(item.guid)
    );
};

const handleTreeNodeEdit = (guid) => {
  selectedTemplateIndex.value = guid;
  handleSelect(guid);
};

const handleTreeNodeDelete = (guid) => {
  handleDelete(guid);
};

const treeDataSource = computed(() => {
  if (
    flowStore.chartConfig.freeChart &&
    flowStore.chartConfig.freeChart.chartTemplates
  ) {
    const keywords = filterContent.value;
    const rawSource = flowStore.chartConfig.freeChart.chartTemplates.map(
      (item) => ({
        id: item.guid,
        label: item.title,
      })
    );
    if (keywords.length) {
      const filteredResults = rawSource.filter((item) => {
        const isApplied =
          flowStore.chartConfig.freeChart.appliedTemplateIndexList.includes(
            item.id
          );
        const itemLabel = item.label.toLowerCase();

        const includeKeywords = keywords.filter(
          (keyword) => !keyword.startsWith("-")
        );
        const excludeKeywords = keywords
          .filter((keyword) => keyword.startsWith("-"))
          .map((keyword) => keyword.substring(1).toLowerCase());

        const hasAllIncludeKeywords = includeKeywords.every((keyword) =>
          itemLabel.includes(keyword.toLowerCase())
        );

        const hasNoExcludeKeywords = excludeKeywords.every(
          (keyword) => !itemLabel.includes(keyword)
        );

        return isApplied || (hasAllIncludeKeywords && hasNoExcludeKeywords);
      });
      return filteredResults;
    } else {
      return rawSource;
    }
  } else {
    return [];
  }
});

const selectedTemplate = ref(null);
const selectedTemplateIndex = ref("");
const selectedTemplateOrigin = ref("");
const selectedSeriesIndex = ref();

const isCreate = ref(false);
const isChanged = computed(() => {
  if (selectedTemplate.value) {
    return (
      JSON.stringify(selectedTemplate.value) != selectedTemplateOrigin.value
    );
  } else {
    return false;
  }
});

const tags = computed(() => flowStore.tags);

const isTagAvailable = (tag) => {
  for (let i = 0; i < selectedTemplate.value.series.length; i++) {
    if (i != selectedSeriesIndex.value) {
      if (selectedTemplate.value.series[i].tags.includes(tag)) {
        return false;
      }
    }
  }
  return true;
};

const selectedTags = computed(() => {
  if (!selectedTemplate.value) {
    return [];
  } else {
    let result = [];
    selectedTemplate.value.series.forEach((series) => {
      result = result.concat(series.tags);
    });
    return result;
  }
});

const handleCreate = () => {
  let guid = randomUUID();
  selectedTemplate.value = {
    guid,
    title: "Chart " + guid.split("-")[0].toUpperCase(),
    description: "",
    total: true,
    series: [
      {
        name: "Series 1",
        tags: [],
        color: randomHexColor(),
      },
    ],
    createTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
    createIP: seatStore.currentSeat.ip,
    updateTime: "-",
    updateIP: "-",
  };
  selectedSeriesIndex.value = 0;
  selectedTemplateIndex.value = selectedTemplate.value.guid;
  isCreate.value = true;
  selectedTemplateOrigin.value = "";
};
const handleAddSeries = () => {
  selectedTemplate.value.series.push({
    name: "Series " + (selectedTemplate.value.series.length + 1),
    tags: [],
    color: randomHexColor(),
  });
  selectedSeriesIndex.value = selectedTemplate.value.series.length - 1;
};
const handleRecolor = () => {
  selectedTemplate.value.series[selectedSeriesIndex.value].color =
    randomHexColor();
};
const handleRemoveSeries = () => {
  if (
    selectedTemplate.value.series.length > 1 &&
    selectedSeriesIndex.value > -1 &&
    selectedSeriesIndex.value < selectedTemplate.value.series.length
  ) {
    let targetIndex = selectedSeriesIndex.value;
    selectedSeriesIndex.value = 0;
    selectedTemplate.value.series.splice(targetIndex, 1);
  }
};

const handleMoveSeries = (offset) => {
  if (
    offset == 1 &&
    selectedSeriesIndex.value < selectedTemplate.value.series.length - 1
  ) {
    let t = selectedTemplate.value.series[selectedSeriesIndex.value + 1];
    selectedTemplate.value.series[selectedSeriesIndex.value + 1] =
      selectedTemplate.value.series[selectedSeriesIndex.value];
    selectedTemplate.value.series[selectedSeriesIndex.value] = t;
  } else if (offset == -1 && selectedSeriesIndex.value > 0) {
    let t = selectedTemplate.value.series[selectedSeriesIndex.value - 1];
    selectedTemplate.value.series[selectedSeriesIndex.value - 1] =
      selectedTemplate.value.series[selectedSeriesIndex.value];
    selectedTemplate.value.series[selectedSeriesIndex.value] = t;
  }
};

const handleSelect = (guid) => {
  const selectedGuid = guid || selectedTemplateIndex.value;
  if (!selectedGuid) {
    ElMessage({
      type: "info",
      message: "No template selected",
    });
    return;
  }
  const target = getTemplateByGuid(selectedGuid, true);
  if (target) {
    selectedTemplateOrigin.value = JSON.stringify(target);
    selectedTemplate.value = target;
    selectedSeriesIndex.value = 0;
  }
};

const getTemplateByGuid = (guid, clone = false) => {
  const array = flowStore.chartConfig.freeChart.chartTemplates;
  // 参数验证
  if (!Array.isArray(array)) {
    throw new Error("chartTemplates必须是数组");
  }
  if (typeof guid !== "string" && typeof guid !== "number") {
    throw new Error("guid值必须是字符串或数字");
  }
  // 查找元素
  const element = array.find((item) => {
    // 确保元素存在且包含guid属性
    return item && item.guid === guid;
  });

  const result = element || null;

  return clone ? JSON.parse(JSON.stringify(result)) : result;
};

const handleReload = () => {
  return new Promise((resolve, reject) => {
    axios
      .post("api/common_params.php", {
        method: "GET",
        keys: ["CHART_TEMPLATES"],
      })
      .then((response) => {
        if (
          response.data &&
          response.data["CHART_TEMPLATES"] &&
          Array.isArray(response.data["CHART_TEMPLATES"])
        ) {
          flowStore.chartConfig.freeChart.chartTemplates =
            response.data["CHART_TEMPLATES"];
          ElMessage({
            message: `已找到 ${response.data["CHART_TEMPLATES"].length} 个模板`,
            type: "info",
          });
        } else {
          ElMessage({
            message: "No templates to load ",
            type: "warning",
          });
        }
        resolve(flowStore.chartConfig.freeChart.chartTemplates);
      })
      .catch((error) => {
        ElMessage({
          message: error.message,
          type: "error",
        });
        console.error(error);
        reject(error);
      });
  });
};

const handleSave = () => {
  return new Promise((resolve, reject) => {
    handleReload().then((data) => {
      let templates = JSON.parse(JSON.stringify(data));
      if (isCreate.value) {
        templates.push(selectedTemplate.value);
      } else {
        for (let i = 0; i < templates.length; i++) {
          if (templates[i].guid == selectedTemplate.value.guid) {
            templates[i] = selectedTemplate.value;
            break;
          }
        }
      }
      selectedTemplate.value.updateTime = dayjs().format("YYYY-MM-DD HH:mm:ss");
      selectedTemplate.value.updateIP = seatStore.currentSeat.ip;

      axios
        .post("api/common_params.php", {
          method: "SET",
          keys: ["CHART_TEMPLATES"],
          values: [templates],
        })
        .then((response) => {
          if (response.data.length && response.data[0]) {
            isCreate.value = false;
            flowStore.chartConfig.freeChart.chartTemplates = templates;
            flowStore.chartConfig.freeChart.appliedTemplateList =
              templates.filter((item) =>
                flowStore.chartConfig.freeChart.appliedTemplateIndexList.includes(
                  item.guid
                )
              );
            ElNotification({
              title: "已保存",
              message: `模板已保存: ${selectedTemplate.value.title}`,
              type: "success",
            });
            handleSelect(selectedTemplate.value.guid);
            // selectedTemplateOrigin.value = "";
            // selectedTemplateIndex.value = "";
            // selectedTemplate.value = null;
            resolve();
          } else {
            ElNotification({
              title: "保存模板的时候失败了~",
              type: "warning",
            });
            reject();
          }
        })
        .catch((error) => {
          ElNotification({
            title: "保存模板的时候失败了~",
            type: "error",
          });
          console.log("handleSave", error);
          reject(error);
        });
    });
  });
};

const handleDelete = (guid) => {
  const selectedGuid = guid || selectedTemplateIndex.value;
  if (!selectedGuid) {
    ElMessage({
      type: "info",
      message: "No template selected to delete",
    });
    return;
  }
  const title = getTemplateByGuid(guid).title || "";
  const verificationCode = randomUUID().split("-")[0].toUpperCase();
  const exactMatchRegex = new RegExp(`^${verificationCode}$`);
  ElMessageBox({
    title: `删除模板 "${title}"`,
    message: h("div", [
      h("p", "确认要删除该模板吗？此操作不可撤销！"),
      h("p", "请输入下方验证码以确认删除:"),
      h(
        "p",
        {
          style: {
            // color: "var(--el-text-color-primary)",
            color: "var(--el-color-danger-light-7)",
            backgroundColor: "var(--el-color-danger)",
            margin: "8px 0",
            padding: "8px",
            fontFamily: "Consolas,monospace",
            fontWeight: "bold",
            fontSize: "24px",
            letterSpacing: "8px",
            textAlign: "center",
            userSelect: "none",
          },
        },
        verificationCode
      ),
    ]),
    showInput: true,
    inputPlaceholder: "请输入验证码 (不区分大小写)",
    inputPattern: exactMatchRegex,
    inputErrorMessage: "验证码错误，无法删除",
    confirmButtonText: "确认删除",
    cancelButtonText: "取消",
    // type: "warning",
  }).then(({ value }) => {
    if (value.trim().toUpperCase() !== verificationCode) {
      ElMessage({
        type: "error",
        message: "验证码错误，已取消删除",
      });
      return;
    }
    handleReload().then((data) => {
      let templates = JSON.parse(JSON.stringify(data));
      let found = false;
      for (let i = 0; i < templates.length; i++) {
        if (templates[i].guid == selectedGuid) {
          templates.splice(i, 1);
          found = true;
          break;
        }
      }
      if (found) {
        axios
          .post("api/common_params.php", {
            method: "SET",
            keys: ["CHART_TEMPLATES"],
            values: [templates],
          })
          .then((response) => {
            if (response.data.length && response.data[0]) {
              flowStore.chartConfig.freeChart.chartTemplates = templates;
              flowStore.chartConfig.freeChart.appliedTemplateList =
                templates.filter((item) =>
                  flowStore.chartConfig.freeChart.appliedTemplateIndexList.includes(
                    item.guid
                  )
                );
              ElNotification({
                title: "已删除模板",
                type: "success",
              });
              selectedTemplate.value = null;
              selectedTemplateIndex.value = "";
            } else {
              handleReload();
              ElNotification({
                title: "删除模板的时候失败了~",
                type: "warning",
              });
            }
          })
          .catch(() => {
            handleReload();
            ElNotification({
              title: "删除模板的时候失败了~",
              type: "error",
            });
          });
      } else {
        selectedTemplate.value = null;
        selectedTemplateIndex.value = "";
        isCreate.value = false;
      }
    });
  });
};

const handleCancelEdit = () => {
  if (isCreate.value || isChanged.value) {
    ElMessageBox.confirm("确认要放弃已经修改的内容吗？", "取消编辑", {
      confirmButtonText: "放弃修改",
      cancelButtonText: "否",
      type: "warning",
    }).then(() => {
      isCreate.value = false;
      selectedTemplate.value = null;
      selectedTemplateIndex.value = "";
      selectedTemplateOrigin.value = "";
    });
  } else {
    isCreate.value = false;
    selectedTemplate.value = null;
    selectedTemplateIndex.value = "";
    selectedTemplateOrigin.value = "";
  }
};

const handleClose = () => {
  flowStore.chartConfig.freeChart.showMgr = false;
};

const handleClear = () => {
  flowStore.chartConfig.freeChart.appliedTemplateIndexList = [];
  flowStore.chartConfig.freeChart.appliedTemplateList = [];
  filterContent.value = [];
};

const removeChartTemplate = (idx) => {
  if (
    idx >= 0 &&
    idx < flowStore.chartConfig.freeChart.appliedTemplateList.length
  ) {
    const guid = flowStore.chartConfig.freeChart.appliedTemplateList[idx].guid;

    const indexInApplied =
      flowStore.chartConfig.freeChart.appliedTemplateIndexList.indexOf(guid);
    const titleApplied =
      indexInApplied > -1
        ? flowStore.chartConfig.freeChart.appliedTemplateList[indexInApplied]
            .title || ""
        : "";
    if (indexInApplied > -1) {
      flowStore.chartConfig.freeChart.appliedTemplateIndexList.splice(
        indexInApplied,
        1
      );
    }
    flowStore.chartConfig.freeChart.appliedTemplateList.splice(idx, 1);
    ElMessage({
      type: "info",
      message: `已移除模板 ${titleApplied}`,
    });
    emits("apply");
  }
};

onMounted(() => {
  // emulateRandomUUID();
  flowStore.chartConfig.freeChart["showMgr"] = true;
  flowStore.chartConfig.freeChart["chartTemplates"] = [];
  flowStore.chartConfig.freeChart["appliedTemplateIndex"] = "";
  flowStore.chartConfig.freeChart["appliedTemplate"] = null;
  handleReload();
});

defineExpose({ removeChartTemplate });
</script>

<style scoped>
.code {
  font-size: 12px;
  font-family: "Consolas", "Courier New", Courier, monospace;
}

.header-container {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.title-container {
  display: flex;
  align-items: center;
  font-weight: bold;
  color: var(--el-text-color-primary);
  font-size: 16px;
}

.title-container > *:not(:last-child) {
  margin-right: 4px;
}

.button-container {
  display: flex;
  align-items: center;
}

.tree-node-group {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 4px;
  align-items: flex-start;
}

.tree-node-group > * {
  width: 100%;
  display: flex;
  align-items: center;
  padding: 2px 4px 2px 12px;
  transition: background-color 0.3s;
}

.tree-node-group > *:hover {
  background-color: var(--el-fill-color-darker);
  /* background-color: var(--el-color-primary-light-7); */
}

.custom-tree-node {
  width: 100%;
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 14px;
  padding-right: 8px;
}

.tree-node-group > * > :not(:first-child) {
  flex: 1;
}

.keywords-options {
  font-size: 12px;
  padding: 0px 2px;
  color: var(--el-text-color-secondary);
}
</style>
